/// Add these libraries to your project's References
/// System
/// Microsoft.SPOT.Net
/// Microsoft.SPOT.Hardware.SerialPort
/// GHIElectronics.NETMF.System
/// GHIElectronics.NETMF.Net
using System;
using Microsoft.SPOT;
using System.IO.Ports;
using System.Text;
using System.Threading;


enum ATSequence
{
    CR_Begin,
    NL_Begin,
    ResultCode,
    CR_End,
    NL_End
};
enum ATstatus
{
    init,
    APsetting,
    Dial,
    Connected,
    Disconnect
};


namespace FEZ_Cobra_Console_Application1
{

    class ATcommander
    {
        SerialPort modem;
        ATstatus atstatus = ATstatus.init;
        ATSequence atsequence = ATSequence.CR_Begin;
        bool clientReq = false;
        public ATcommander(SerialPort serial)
        {
            modem = serial;
        }

        public bool ClientConnectModem()
        {
            bool con = false;
            int trial = 0;
            int size = 0;
            String message;
            byte[] buffer = new byte[125];
            if (clientReq == false)
            {


                clientReq = true;
                atstatus = ATstatus.init;
                atsequence = ATSequence.CR_Begin;
                modem.Write(new byte[] { 0x7E, 0xFF, 0x7D, 0x23, 0xC0, 0x21, 0x7D, 0x25, 0x7D, 0x2A, 0x7D, 0x20, 0x7D, 0x30, 0x2B, 0xD3, 0x45, 0xAF, 0x7D, 0x20, 0x3C, 0xCD, 0x74, 0x7D, 0x20, 0x7D, 0x20, 0x7D, 0x20, 0x7D, 0x20, 0x2A, 0x9D, 0x7E }, 0, 34);// Terminate request          
                modem.Write(Encoding.UTF8.GetBytes("\r+++"), 0, 4);// Escape Sequence
                Thread.Sleep(3000);
                modem.Write(Encoding.UTF8.GetBytes("ATH\r"), 0, 4); // Hook On
                Thread.Sleep(1000);
                modem.Write(Encoding.UTF8.GetBytes("ATZ\r"), 0, 4); // Soft Reset, basic default restore
                Thread.Sleep(100);
                modem.Write(Encoding.UTF8.GetBytes("ATE\r"), 0, 4); // Echo Disabled
                Thread.Sleep(100);
                modem.DiscardInBuffer();
                // modem.DataReceived += new SerialDataReceivedEventHandler(modem_DataReceived);
                modem.Write(Encoding.UTF8.GetBytes("AT+FLO=2\r"), 0, 9);// Enable handshaking
                //Thread.Sleep(1000);
                //modem.Write(Encoding.UTF8.GetBytes("AT\r"), 0, 3);
                Thread.Sleep(100);


                while (!con)
                {
                    size = modem.Read(buffer, 0, modem.BytesToRead);
                    for (int i = 0; i < size; i++)
                    {
                        Debug.Print(((char)buffer[i]).ToString());

                        // AT stuff//////////////////////
                        message = GetATResultCode(buffer[i]);
                        if (message != null)
                        {
                            Debug.Print(message);
                            con = ProcessAT(message);
                        }
                        /////////////////////////////////
                    }

                    trial++;
                    if (trial > 200000)// trials
                    {

                        clientReq = false;
                        return false;
                    }
                    Thread.Sleep(100);
                }
                clientReq = false;
                return true;
            }
            return false;

        }

        private bool ProcessAT(String message)
        {
            switch (atstatus)
            {
                case ATstatus.init:
                    if (message == "OK")
                    {
                        atstatus = ATstatus.APsetting;
                        modem.Write(Encoding.UTF8.GetBytes("AT+cgdcont=2,\"IP\",\"wap.cingular\"\r"), 0, 33);
                        //modem.Write(Encoding.UTF8.GetBytes("AT+CGDCONT=1,\"IP\",\"isp.cingular\"\r"), 0, 33);
                        Debug.Print("WRITE: AT+CGDCONT=1,\"IP\",\"isp.cingular\"\r");
                    }
                    break;
                case ATstatus.APsetting:
                    if (message == "OK")
                    {
                        atstatus = ATstatus.Dial;
                        modem.Write(Encoding.UTF8.GetBytes("ATDT*99***2#\r"), 0, 13);
                    }
                    break;
                case ATstatus.Dial:
                    if (message == "CONNECT")
                    {
                        atstatus = ATstatus.Connected;
                        Debug.Print("AT connected, Ready for PPP connection Establishing!");
                        return true;
                    }
                    else
                    {
                        modem.Write(Encoding.UTF8.GetBytes("ATDT*99***2#\r"), 0, 13);
                    }
                    break;
            }
            return false;

        }


        static byte[] ResultCodeBuffer = new byte[32];
        int index = 0;

        private String GetATResultCode(byte s)
        {

            switch (atsequence)
            {
                case ATSequence.CR_Begin:
                    if (s == 0x0D)
                        atsequence = ATSequence.NL_Begin;
                    break;
                case ATSequence.NL_Begin:
                    if (s == 0x0A)
                    {
                        atsequence = ATSequence.ResultCode;
                        index = 0;
                    }
                    else
                    {
                        atsequence = ATSequence.CR_Begin;
                    }
                    break;
                case ATSequence.ResultCode:
                    if (s == 0x0D)
                    {
                        if (index != 0)
                            atsequence = ATSequence.NL_End;
                        else
                            atsequence = ATSequence.NL_Begin;
                    }
                    else if (s == 0x0A)
                        atsequence = ATSequence.CR_Begin;
                    else
                    {
                        ResultCodeBuffer[index++] = s;
                    }
                    break;
                case ATSequence.CR_End:
                    if (s == 0x0D)
                        atsequence = ATSequence.NL_End;
                    else
                    {
                        atsequence = ATSequence.CR_Begin;
                    }
                    break;
                case ATSequence.NL_End:
                    if (s == 0x0A)
                    {
                        atsequence = ATSequence.CR_Begin;

                        return new String(Encoding.UTF8.GetChars(ResultCodeBuffer), 0, index);
                    }
                    break;
            }
            return null;
        }

    }
}
